/*
 * pgp-info.c
 *	  提供关于 PGP 数据的信息。
 *
 * Copyright (c) 2005 Marko Kreen
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *	  notice, this list of 条件和以下免责声明。
 * 2. Redistributions in binary form must reproduce the above copyright
 *	  notice, this list of条件和以下免责声明在文档和/或其他提供的材料
 * 与分发一起。
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 或后果
 * 损害（包括但不限于替代商品或服务的采购；丧失使用、数据或利润；或业务中断）
 * 无论因何原因以及在任何责任理论下，无论是合同、严格
 * 责任或侵权行为（包括疏忽或其他）以任何方式产生
 * 出于对本软件的使用，即使在被告知有可能发生
 * 这样的损害。
 *
 * contrib/pgcrypto/pgp-info.c
 */
#include "postgres.h"

#include "mbuf.h"
#include "pgp.h"
#include "px.h"

static int fc_read_pubkey_keyid(PullFilter *fc_pkt, uint8 *fc_keyid_buf)
{
	int			fc_res;
	PGP_PubKey *fc_pk = NULL;

	fc_res = _pgp_read_public_key(fc_pkt, &fc_pk);
	if (fc_res < 0)
		goto err;

	/* 跳过秘密密钥部分，如果存在的话 */
	fc_res = pgp_skip_packet(fc_pkt);
	if (fc_res < 0)
		goto err;

	/* 这是加密密钥吗 */
	switch (fc_pk->algo)
	{
		case PGP_PUB_ELG_ENCRYPT:
		case PGP_PUB_RSA_ENCRYPT:
		case PGP_PUB_RSA_ENCRYPT_SIGN:
			memcpy(fc_keyid_buf, fc_pk->key_id, 8);
			fc_res = 1;
			break;
		default:
			fc_res = 0;
	}

err:
	pgp_key_free(fc_pk);
	return fc_res;
}

static int fc_read_pubenc_keyid(PullFilter *fc_pkt, uint8 *fc_keyid_buf)
{
	uint8		fc_ver;
	int			fc_res;

	GETBYTE(fc_pkt, fc_ver);
	if (fc_ver != 3)
		return -1;

	fc_res = pullf_read_fixed(fc_pkt, 8, fc_keyid_buf);
	if (fc_res < 0)
		return fc_res;

	return pgp_skip_packet(fc_pkt);
}

static const char hextbl[] = "0123456789ABCDEF";

static int fc_print_key(uint8 *fc_keyid, char *fc_dst)
{
	int			fc_i;
	unsigned	fc_c;

	for (fc_i = 0; fc_i < 8; fc_i++)
	{
		fc_c = fc_keyid[fc_i];
		*fc_dst++ = hextbl[(fc_c >> 4) & 0x0F];
		*fc_dst++ = hextbl[fc_c & 0x0F];
	}
	*fc_dst = 0;
	return 8 * 2;
}

static const uint8 any_key[] =
{0, 0, 0, 0, 0, 0, 0, 0};

/*
 * dst 应该有足够的空间容纳 17 字节
 */
int pgp_get_keyid(MBuf *fc_pgp_data, char *fc_dst)
{
	int			fc_res;
	PullFilter *fc_src;
	PullFilter *fc_pkt = NULL;
	int			fc_len;
	uint8		fc_tag;
	int			fc_got_pub_key = 0,
				fc_got_symenc_key = 0,
				fc_got_pubenc_key = 0;
	int			fc_got_data = 0;
	uint8		fc_keyid_buf[8];
	int			fc_got_main_key = 0;


	fc_res = pullf_create_mbuf_reader(&fc_src, fc_pgp_data);
	if (fc_res < 0)
		return fc_res;

	while (1)
	{
		fc_res = pgp_parse_pkt_hdr(fc_src, &fc_tag, &fc_len, 0);
		if (fc_res <= 0)
			break;
		fc_res = pgp_create_pkt_reader(&fc_pkt, fc_src, fc_len, fc_res, NULL);
		if (fc_res < 0)
			break;

		switch (fc_tag)
		{
			case PGP_PKT_SECRET_KEY:
			case PGP_PKT_PUBLIC_KEY:
				/* 主密钥用于签名，所以忽略它 */
				if (!fc_got_main_key)
				{
					fc_got_main_key = 1;
					fc_res = pgp_skip_packet(fc_pkt);
				}
				else
					fc_res = PXE_PGP_MULTIPLE_KEYS;
				break;
			case PGP_PKT_SECRET_SUBKEY:
			case PGP_PKT_PUBLIC_SUBKEY:
				fc_res = fc_read_pubkey_keyid(fc_pkt, fc_keyid_buf);
				if (fc_res < 0)
					break;
				if (fc_res > 0)
					fc_got_pub_key++;
				break;
			case PGP_PKT_PUBENCRYPTED_SESSKEY:
				fc_got_pubenc_key++;
				fc_res = fc_read_pubenc_keyid(fc_pkt, fc_keyid_buf);
				break;
			case PGP_PKT_SYMENCRYPTED_DATA:
			case PGP_PKT_SYMENCRYPTED_DATA_MDC:
				/* 不要跳过它，仅仅停止 */
				fc_got_data = 1;
				break;
			case PGP_PKT_SYMENCRYPTED_SESSKEY:
				fc_got_symenc_key++;
				/* fall through */
			case PGP_PKT_SIGNATURE:
			case PGP_PKT_MARKER:
			case PGP_PKT_TRUST:
			case PGP_PKT_USER_ID:
			case PGP_PKT_USER_ATTR:
			case PGP_PKT_PRIV_61:
				fc_res = pgp_skip_packet(fc_pkt);
				break;
			default:
				fc_res = PXE_PGP_CORRUPT_DATA;
		}

		if (fc_pkt)
			pullf_free(fc_pkt);
		fc_pkt = NULL;

		if (fc_res < 0 || fc_got_data)
			break;
	}

	pullf_free(fc_src);
	if (fc_pkt)
		pullf_free(fc_pkt);

	if (fc_res < 0)
		return fc_res;

	/* 现在检查有效性 */
	if (fc_got_pub_key && fc_got_pubenc_key)
		fc_res = PXE_PGP_CORRUPT_DATA;

	if (fc_got_pub_key > 1)
		fc_res = PXE_PGP_MULTIPLE_KEYS;

	if (fc_got_pubenc_key > 1)
		fc_res = PXE_PGP_MULTIPLE_KEYS;

	/*
	 * 如果仍然正常，看看我们得到了什么
	 */
	if (fc_res >= 0)
	{
		if (fc_got_pubenc_key || fc_got_pub_key)
		{
			if (memcmp(fc_keyid_buf, any_key, 8) == 0)
			{
				memcpy(fc_dst, "ANYKEY", 7);
				fc_res = 6;
			}
			else
				fc_res = fc_print_key(fc_keyid_buf, fc_dst);
		}
		else if (fc_got_symenc_key)
		{
			memcpy(fc_dst, "SYMKEY", 7);
			fc_res = 6;
		}
		else
			fc_res = PXE_PGP_NO_USABLE_KEY;
	}

	return fc_res;
}
